/**
 * 
 */
package com.ly.sms.utils;

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.Temporal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;

/**
 * Jackson Json 工具类
 */
public class JsonUtils {
  protected static ObjectMapper objectMapper;

  static {
    objectMapper = new ObjectMapper();
    config(objectMapper);
  }

  /**
   * 配置ObjectMapper
   * 
   * @param objectMapper
   */
  public static void config(ObjectMapper objectMapper) {
    // 允许单引号字段
    objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);

    // 允许无引号字段
    objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
    // objectMapper.configure(JsonGenerator.Feature.QUOTE_FIELD_NAMES,
    // false);


    // 反序列化时碰到未知字段时不报错
    objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    // objectMapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE,
    // true);
    // objectMapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);

    // 只序列化非空字段
    objectMapper.setSerializationInclusion(Include.NON_NULL);

    // fastxml默认的时区为UST,必须手动设置为CST,否则序列化后时间会落后8小时
    objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));
    DateFormat sdf = new SimpleDateFormat(DateTimeUtils.BASIC_DATE_TIME_PATTERN);
    objectMapper.setDateFormat(sdf);

    jdk8Support(objectMapper);
  }

  /**
   * JDK8支持
   * 
   * @param objectMapper
   */
  public static void jdk8Support(ObjectMapper objectMapper) {
    // objectMapper.registerModule(new ParameterNamesModule());
    objectMapper.registerModule(new Jdk8Module());

    // JDK8 Time支持
    objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

    JavaTimeModule javaTimeModule = new JavaTimeModule();
    DateTimeFormatter dateTimeFormatter =
        DateTimeFormatter.ofPattern(DateTimeUtils.BASIC_DATE_TIME_PATTERN);

    DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern(DateTimeUtils.BASIC_DATE_PATTERN);

    DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern(DateTimeUtils.BASIC_TIME_PATTERN);


    // 反序列化日期时间默认格式设置
    javaTimeModule.addDeserializer(LocalDateTime.class,
        new LocalDateTimeDeserializer(dateTimeFormatter));
    javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(dateFormatter));
    javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(timeFormatter));

    // 序列化日期时间默认格式设置
    javaTimeModule.addSerializer(LocalDateTime.class,
        new LocalDateTimeSerializer(dateTimeFormatter));
    javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(dateFormatter));
    javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(timeFormatter));

    objectMapper.registerModule(javaTimeModule);
  }

  /**
   * 如需单独使用ObjectMapper,请在获取后调用copy(),以免影响公用mapper<br/>
   * 
   * <pre>
   * {
   *   &#64;code
   *   ObjectMapper objectMapper = JsonUtils.getObjectMapper().copey();
   *   objectMapper.setSerializationInclusion(Include.NON_NULL);
   * }
   * </pre>
   * 
   * @return
   */
  public static ObjectMapper getObjectMapper() {
    return objectMapper;
  }

  public static String toJson(Object src) {
    try {
      return objectMapper.writeValueAsString(src);
    } catch (JsonProcessingException e) {
      e.printStackTrace();
    }
    return null;
  }

  public static String toJsonIncludeAlways(Object src) {
    try {
      ObjectMapper objectMapper = JsonUtils.getObjectMapper().copy();
      objectMapper.setSerializationInclusion(Include.ALWAYS);
      return objectMapper.writeValueAsString(src);
    } catch (JsonProcessingException e) {
      e.printStackTrace();
    }
    return null;
  }

  public static <T> T fromJson(JsonNode node, TypeReference<T> valueTypeRef)
      throws JsonParseException, JsonMappingException, IOException {
    return objectMapper.readValue(objectMapper.treeAsTokens(node), valueTypeRef);
  }

  public static <T> T fromJson(String src, Class<T> type)
      throws JsonParseException, JsonMappingException, IOException {
    return objectMapper.readValue(src, type);
  }

  /**
   * Json数组转换为List
   * 
   * @param src
   * @param type
   * @return
   * @throws JsonParseException
   * @throws JsonMappingException
   * @throws IOException
   */
  public static <T> List<T> fromJsonToList(String src, Class<T> type)
      throws JsonParseException, JsonMappingException, IOException {
    JavaType javaType = objectMapper.getTypeFactory().constructParametricType(List.class, type);
    return objectMapper.readValue(src, javaType);
  }

  public static <T> T fromJson(InputStream is, Class<T> type)
      throws JsonParseException, JsonMappingException, IOException {
    return objectMapper.readValue(is, type);
  }

  public static <T> T fromJson(Reader reader, Class<T> type)
      throws JsonParseException, JsonMappingException, IOException {
    return objectMapper.readValue(reader, type);
  }

  /**
   * Json对象转换为Map
   * 
   * @param src
   * @return
   * @throws JsonParseException
   * @throws JsonMappingException
   * @throws IOException
   */
  public static Map<String, Object> fromJsonToMap(String src)
      throws JsonParseException, JsonMappingException, IOException {
    return objectMapper.readValue(src, new TypeReference<HashMap<String, Object>>() {});
  }

  public static <T> T fromJson(String content, TypeReference<T> valueTypeRef)
      throws IOException, JsonParseException, JsonMappingException {
    return objectMapper.readValue(content, valueTypeRef);
  }

  public static void main(String[] str) throws Exception {
    Map<String, Temporal> map = new HashMap<String, Temporal>();
    map.put("LocalTime", LocalTime.now());
    map.put("LocalDate", LocalDate.now());
    map.put("LocalDateTime", LocalDateTime.now());
    System.out.println(JsonUtils.toJson(map));

    System.out.println(JsonUtils.toJson(LocalDateTime.now()));
  }
}
